/* 
 * Quechua modules - modules forthe lightweight data mining framework
 *
 * Copyright (C) 2012 Marek Denis <quechua@octogan.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef QUECHUA_H
#define	QUECHUA_H

#include <cstdio>
#include <map>
#include <ev++.h>
#include <libconfig.h++>
#include <unistd.h>
#include "../config.h"
#include "types.h"
#include "modules.h"
#include "workflow.h"
#include "interface.h"
#include "log.h"
#include "threads.h"
#include "python-interface.h"

static const string_t default_path = "/opt/quechua/etc/quechua.conf";

class Config {
 public:
     configuration_t *configuration;
     string_t path;
     const string_t version;
     
     Config() : version("0.1") {
         configuration = new(nothrow) configuration_t();
         if(!configuration) {
             LOG(ERROR) << "Couldn't allocate memory for configuration";
             exit(EXIT_FAILURE);
         }
     }

     virtual ~Config() {
         delete configuration;
     }
     
     int load() {
         int result = 0;
         try {
             if(path.empty()) {
                 LOG(WARN) << "Using default config filename";
                 path = default_path;
             }
             
             LOG(INFO) << "Loading configuration file " << path << " ...";
             configuration->readFile(path.c_str());
             
         } catch(file_io_ex& ex) {
             result = -1;
         } catch(parse_ex& ex) {
             result = -2;
         } catch(setting_ex& ex) {
             result = -3;
         }

         return result;      
     };

     bool check_version() {
        configuration_t& c = *configuration;
        if(!configuration || !c.exists("version"))
            return false;
        string_t v;
        c.lookupValue("version",v);
        return compare_version(v);
     };

 protected:
     bool compare_version(const string_t& ver) {
        if(!version.compare(ver)) return true;
        return false;
     };
};

class Quechua {

 struct signals_s {
     ev::sig sigint;
     ev::sig sigsegv;
 };
 
 struct components_s {
     channels_map channels;
     workflows_map workflows;
     loggers_map loggers;
 };
 
 public:
     Quechua() {
         init();
     }
     virtual ~Quechua(); 
    
     void init(); 
    
     void run() {
         LOG(INFO) << "Running Quechua";
         loop->run(0);
     }

     void prepare_channels();
     void prepare_workflows();
     void prepare_loggers();
 
     void prepare_signals();

     void start_channels();
     void start_workflows(); //think about it
     void start_loggers();
 
     void stop_channels();
     void stop_workflows();
     void stop_loggers();
     void stop_signals();
 
     void destroy_channels();
     void destroy_workflows();
     void destroy_loggers();

     void daemonize();

     
     Threads *threads; // struct for managing threads
     Modules *modules; // struct for managing dynamically loaded modules
     Config  *config;  // loading configurations
     Logging *logs;
     components_s *components;
     signals_s* signals;
     
     ev::default_loop* loop; // main loop of the application 
 };


/*** SIGNAL HANDLERS ***/
void sigint_cb(ev::sig &watcher, int revents);
//void sigsegv_cb(eV::signal &watcher, int revents);
/***********************/


extern Quechua *g_quechua;

#endif	/* QUECHUA_H */

